package com.jbob.parser;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.tartarus.snowball.SnowballStemmer;
import org.tartarus.snowball.ext.frenchStemmer;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.jbob.collection.Balise;
import com.jbob.collection.DocumentXml;
import com.jbob.collection.Qrel;
import com.jbob.collection.QueriesXml;
import com.jbob.collection.Query;
import com.jbob.constants.CONSTANTS;

/**
 * Classe en charge de g�rer l'aspect parsing des donn�es
 * @author lucas.bouabdelli jean-baptiste.guy
 */
public class ParserHelper 
{
	private static ArrayList<String> stopList;
	private static Set<String> termsList = new HashSet<>(); // Permet d'avoir une lsite de termes sans doublons
	private static ArrayList<DocumentXml> documentsList = new ArrayList<>();
	
	public static void parseFolder(String pathFolder) {
		System.out.println(" -- D�but du parsing -- ");
		getStopList();
		// On se place dans le dossier contenant les fichiers
		File dir = new File(pathFolder);
		if(dir.exists() && dir.isDirectory())
		{
			FileFilter filter = new FileFilter() 
			{
				@Override
				public boolean accept(File pathname) 
				{
					return pathname.getName().contains(".xml") && pathname.getName().startsWith("d");
				}
			};
			
			File[] files = dir.listFiles(filter);
			for(File f : files)
			{
				System.out.println("\t" + f);
				ParserHelper.parseFile(f);
			}
		}
		System.out.println(" -- Fin du parsing -- ");
	}
	
	private static void parseFile(File xmlFile)
	{
		DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder;
		
		try 
		{
			// Cr�ation de l'objet Document
			DocumentXml document = new DocumentXml();
			document.setName(xmlFile.getName());
			
			// D�but de l'op�ration de parsing
			builder = fact.newDocumentBuilder();
			Document doc = builder.parse(xmlFile);
			NodeList nodeList = doc.getDocumentElement().getElementsByTagName(CONSTANTS.NODE_P);
			for(int i = 0 ; i < nodeList.getLength() ; i++)
			{
				// Cr�ation de l'objet balise
				Balise balise = new Balise();
				balise.setName(nodeList.item(i).getNodeName()); 
				balise.setPath(getNodePath(nodeList.item(i)));
				
				// traitement des mots pr�sents dans la balise
				treatPNode(nodeList.item(i).getTextContent(), balise);
				document.addBalise(balise);
				//System.out.println(document.toString());
			}
			documentsList.add(document);
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
	}
	
	public static QueriesXml parseRequest(File xmlFile)
	{
		QueriesXml queries = null;
				
		DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder;
		
		try 
		{
			// Cr�ation de l'objet Query
			queries = new QueriesXml(xmlFile.getName());
			
			// D�but de l'op�ration de parsing
			builder = fact.newDocumentBuilder();
			Document doc = builder.parse(xmlFile);
			NodeList nodeList = doc.getElementsByTagName(CONSTANTS.NODE_TEXT);
			for(int i = 0 ; i < nodeList.getLength() ; i++)
			{
				Node node = nodeList.item(i);
				int num = i+1;
				String id = "";
				if (num < 10 ) {
					id = "0" + num;
				} else {
					id = "" +num;
				}
				queries.addQuery(new Query(id, node.getTextContent(), ""));
			}
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
		
		
		return queries;
	}
	
	public static void treatPNode(String nodeContent, Balise balise)
	{
		SnowballStemmer stemmer = new frenchStemmer();
		
		nodeContent = nodeContent.toLowerCase();
		// retrait de toute la ponctuation et des guillemets anglais
		nodeContent = nodeContent.replaceAll("\\p{Punct}|«|»", " ");
		// Split sur tout espace qu'il s'agisse d'une tab, d'un espace simple, d'un saut de ligne ou autre
		nodeContent = nodeContent.trim();
		String[] content = nodeContent.split("\\p{Space}");
		
		for(int i = 0 ; i < content.length ; i++)
		{
			String str = content[i];
			if(str != null && !str.isEmpty() && !stopList.contains(str))
			{
				stemmer.setCurrent(str);
				stemmer.stem();
				String stemmedString = stemmer.getCurrent();
				
				termsList.add(stemmedString);
				balise.addTerm(stemmedString, i);
			}
		}
	}
	
	private static void createStopListArray() throws IOException
	{
		stopList = new ArrayList<String>();
	    byte[] encoded = Files.readAllBytes(Paths.get("./files/stoplist.txt"));
	    Charset encoding = Charset.forName("UTF8");
	    String result = encoding.decode(ByteBuffer.wrap(encoded)).toString();
	    String[] strings = result.split("\\p{Space}");
	    for(String str : strings)
	    {
	    	stopList.add(str);
	    }
	}
	
	/**
	 * M�thode r�cursive de r�cup�ration des noms du noeud
	 * @param node
	 * @return
	 */
	private static String getNodePath(Node node)
	{
		// Utilisation d'un string builder inutile dans une m�thode r�cursive 
		if(!node.getNodeName().equals(CONSTANTS.NODE_BALADE))
		{
			Node parent = node.getParentNode();
			Node n = node;
			int nb = 1;
			// Brique de code de parcours des �l�ments pr�c�dents afin de d�terminer le num�ro de la borne
			while(n.getPreviousSibling() != null)
			{
				if(n.getPreviousSibling().getNodeName().equals(node.getNodeName()))
				{
					nb++;
				}
				n = n.getPreviousSibling();
			}
			return getNodePath(parent) + "/" + node.getNodeName() + "[" + nb + "]";
		}
		return CONSTANTS.NODE_BALADE + "[1]"; // La borne BALADE est unique dans un document
	}

	public static ArrayList<String> getStopList() 
	{
		if(stopList == null)
		{
			try {
				createStopListArray();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return stopList;
	}
	
	public static ArrayList<Qrel> parseQueryResultFile(File file) throws IOException
	{
		FileReader reader = new FileReader(file);
		BufferedReader bufRead = new BufferedReader(reader);
		String line = null;
		ArrayList<Qrel> qrels = new ArrayList<>();
		while((line = bufRead.readLine()) != null)
		{
			Qrel qrel = new Qrel(line);
			if(qrel.isPertinent())
			{
				qrels.add(qrel);
			}
		}
		bufRead.close();
		return qrels;
	}

	public static void setStopList(ArrayList<String> stopList) {
		ParserHelper.stopList = stopList;
	}

	public static Set<String> getTermsList() {
		return termsList;
	}

	public static void setTermsList(Set<String> termsList) {
		ParserHelper.termsList = termsList;
	}

	public static ArrayList<DocumentXml> getDocumentsList() {
		return documentsList;
	}

	public static void setDocumentsList(ArrayList<DocumentXml> documentsList) {
		ParserHelper.documentsList = documentsList;
	}
}
